package com.example.common.utils;

import com.alibaba.nacos.common.utils.StringUtils;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.example.common.constants.FileConstants;
import com.example.common.properties.AliProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;


@Data
@AllArgsConstructor
@Component
@Slf4j
public class AliOssUtil {
    private static final long PART_SIZE = 10 * 1024 * 1024; // 10MB
    // 默认重试次数
    private static final int DEFAULT_RETRY_TIMES = 3;

    //    private static final String endpoint = "https://oss-cn-beijing.aliyuncs.com";
//    private static final String accessKeyId = "LTAI5tMxeWnxgogzqgjQCGr8";
//    private static final String accessKeySecret = "JsC4GLYj2AfFt2d75kc6XMNMLpRR5T";
//    private static final String bucketName = "yyz-soft";
    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    // 注入配置类
    @Autowired
    public AliOssUtil(AliProperties properties) {
        this.endpoint = properties.getEndpoint();
        this.accessKeyId = properties.getAccessKeyId();
        this.accessKeySecret = properties.getAccessKeySecret();
        this.bucketName = properties.getBucketName();
        System.out.println("AliOssUtil配置完成");
    }

    private String getContentTypeByFileName(String fileName) {
        if (fileName.endsWith(".png") || fileName.endsWith(".PNG")) {
            return "image/png";
        } else if (fileName.endsWith(".jpg") || fileName.endsWith(".JPG") ||
                fileName.endsWith(".jpeg") || fileName.endsWith(".JPEG")) {
            return "image/jpeg";
        } else if (fileName.endsWith(".gif") || fileName.endsWith(".GIF")) {
            return "image/gif";
        } else if (fileName.endsWith(".pdf") || fileName.endsWith(".PDF")) {
            return "application/pdf";
        } else if (fileName.endsWith(".txt") || fileName.endsWith(".TXT")) {
            return "text/plain";
        } else if (fileName.endsWith(".html") || fileName.endsWith(".HTML")) {
            return "text/html";
        } else if (fileName.endsWith(".mp4") || fileName.endsWith(".MP4")) {
            return "video/mp4";
        } else if (fileName.endsWith(".mp3") || fileName.endsWith(".MP3")) {
            return "audio/mpeg";
        }
        // 默认二进制流类型
        return "application/octet-stream";
    }

    public String generateImageFileName(String userId) {
        LocalDate now = LocalDate.now(); // 获取当前日期
        // 生成5位UUID随机字符串
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 5);

        return String.format("%d-%d-%d-%d-%s%s",
                userId,
                now.getYear(),
                now.getMonthValue(),
                now.getDayOfMonth(),
                uuid);
    }

    public String uploadImgToAlibaba(MultipartFile file) throws Exception {
        String originalFileName = file.getOriginalFilename();
        String fileName = UUID.randomUUID() + originalFileName.substring(originalFileName.lastIndexOf("."));
        String url = upLoadFile(fileName, file.getInputStream());
        return url;
    }

    //上传文件
    public String saveFile(String fileName, Object fileContent) throws Exception {
        InputStream inputStream = null;
            // 处理不同类型的文件内容（MultipartFile/byte[]/InputStream）
            if (fileContent instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) fileContent;
                inputStream = file.getInputStream();
            } else if (fileContent instanceof InputStream) {
                inputStream = (InputStream) fileContent;
            } else {
                log.error("不支持该文件类型！！！");
                throw new IllegalArgumentException("不支持的文件类型");
            }
        String url = upLoadFile(fileName, inputStream);
        return url;
    }

    public String uploadImgUser(MultipartFile file,String type) throws Exception {
        String originalFileName = file.getOriginalFilename();
        String fileName =type +             //指定目标文件夹
                originalFileName.substring(originalFileName.lastIndexOf("."));
        String url = upLoadFile(fileName, file.getInputStream());
        return url;
    }


    public String upLoadFile(String objectName, InputStream in) throws Exception {
endpoint = "https://oss-cn-beijing.aliyuncs.com";
accessKeyId = "LTAI5tMxeWnxgogzqgjQCGr8";
 accessKeySecret = "JsC4GLYj2AfFt2d75kc6XMNMLpRR5T";
 bucketName = "yyz-soft";
        System.out.println("e:" + endpoint);
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        String url = "";

        try {
            ObjectMetadata metadata = new ObjectMetadata();
            String contentType = getContentTypeByFileName(objectName);
            metadata.setContentType(contentType); // 获取正确的MIME类型
            // 可选：设置 Content-Disposition 以控制对象被访问时的行为  attachment强制下载
            metadata.setContentDisposition("inline"); // inline显示图片文件，而不是下载
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, in, metadata);  //上传图片
            PutObjectResult result = ossClient.putObject(putObjectRequest);   //发送请求
//            System.out.println(result.getResponse().getStatusCode());    //获取请求之后的状态码
            url = "https://" + bucketName + "." + endpoint.substring(endpoint.lastIndexOf("/") + 1) + "/" + objectName;
            System.out.println("上传到云端的图片的url为：" + url);
        } catch (OSSException oe) {
            System.out.println("捕获到一个OSSException，这意味着您的请求已到达OSS，但由于某种原因被拒绝并返回了错误响应。.");
            System.out.println("错误消息:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("捕获到一个 ClientException，这意味着客户端在尝试与 OSS 进行通信时遇到了严重的内部问题，例如无法访问网络。.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return url;
    }


    public boolean deleteFile(String objectName) {
        if (StringUtils.isEmpty(objectName)) {
            log.error("删除文件失败，文件路径为空");
            return false;
        }
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 检查文件是否存在
            if (!ossClient.doesObjectExist(bucketName, objectName)) {
                log.warn("文件不存在，无需删除，路径: {}", objectName);
                return true; // 文件不存在时也视为操作成功
            }
            // 删除文件
            ossClient.deleteObject(bucketName, objectName);
            log.info("文件删除成功，路径: {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("OSS删除异常，路径: {}, 错误码: {}, 消息: {}",
                    objectName, oe.getErrorCode(), oe.getErrorMessage());
        } catch (ClientException ce) {
            log.error("OSS客户端异常，路径: {}, 消息: {}", objectName, ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return false;
    }


    // 在AliOssUtil中添加分片上传方法
    public String uploadLargeFile(String objectName, InputStream inputStream, long fileSize) throws Exception {
        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 1. 初始化分片上传
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
            InitiateMultipartUploadResult initResult = ossClient.initiateMultipartUpload(initRequest);
            String uploadId = initResult.getUploadId();

            // 2. 计算分片数量（每片10MB）
            int partCount = (int) ((fileSize + PART_SIZE - 1) / PART_SIZE);    //每次分片10MB
            if (partCount > 10000) {
                log.error("文件过大，分片数量超过限制");
                throw new IllegalArgumentException("文件过大，分片数量超过限制");
            }

            // 3. 逐个上传分片
            List<PartETag> partETags = new ArrayList<>();
            for (int i = 0; i < partCount; i++) {
                // 定位分片位置
                long startPos = i * PART_SIZE;
                long curPartSize = Math.min(PART_SIZE, fileSize - startPos);

                // 上传分片
                inputStream.skip(startPos);
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(bucketName);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(inputStream);
                uploadPartRequest.setPartSize(curPartSize);
                uploadPartRequest.setPartNumber(i + 1);

                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                partETags.add(uploadPartResult.getPartETag());

                // 重置输入流位置
                inputStream.reset();
            }

            // 4. 完成分片上传
            CompleteMultipartUploadRequest completeRequest =
                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
            ossClient.completeMultipartUpload(completeRequest);

            // 5. 构建访问URL
            return "https://" + bucketName + "." + endpoint.substring(endpoint.lastIndexOf("/") + 1) + "/" + objectName;
        } catch (Exception e) {
            log.error("分片上传异常，objectName: {}", objectName, e);
            throw e;
        } finally {
            ossClient.shutdown();
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }


}
